﻿@page "/pages/authentication/loginwithrecoverycode"
@using CleanArchitecture.Blazor.Domain.Identity
@using System.ComponentModel.DataAnnotations

@inject IStringLocalizer<LoginWithRecoveryCode> L
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
@inject IdentityRedirectManager RedirectManager
@inject ILogger<LoginWithRecoveryCode> Logger

<PageTitle>@L["Recovery code verification"]</PageTitle>

<MudText Typo="Typo.h4" GutterBottom="true">@L["Recovery code verification"]</MudText>

<MudText Typo="Typo.body1">
    @L["You have requested to log in with a recovery code. This login will not be remembered until you provide an authenticator app code at log in or disable 2FA and log in again."]
</MudText>

<div class="d-flex flex-column gap-y-3">
    <div class="d-flex flex-column">
        <EditForm Model="Input" FormName="login-with-recovery-code" OnValidSubmit="OnValidSubmitAsync" method="post">
            <DataAnnotationsValidator/>
            <StatusMessage Message="@message" Error="true"/>

            <div class="mud-input-control mud-input-input-control my-4">
                <div class="mud-input-control-input-container">
                    <!--!--><!--!-->
                    <div class="mud-input mud-input-outlined mud-shrink">
                        <InputText @bind-Value="Input.RecoveryCode" class="mud-input-slot mud-input-root mud-input-root-outlined" type="text" autocomplete="off" aria-required="true"/>
                        <div class="mud-input-slot mud-input-root mud-input-root-outlined" style="display:none"></div>
                        <!--!-->
                        <div class="mud-input-outlined-border"></div>
                    </div>
                    <!--!-->
                    <label class="mud-input-label mud-input-label-animated mud-input-label-outlined mud-input-label-inputcontrol" for="recoveryCode">@L["Recovery Code"]</label>
                </div>
                <div class="mud-input-helper-text mud-input-error">
                    <div class="d-flex">
                        <ValidationMessage For="() => Input.RecoveryCode" class="mud-input-error"/>
                    </div>
                </div>
            </div>

            <div>
                <MudButton Variant="Variant.Filled"
                           Color="Color.Primary"
                           Size="Size.Large"
                           ButtonType="ButtonType.Submit"
                           FullWidth="true">
                    <MudText>@L["Sign In"]</MudText>
                </MudButton>
            </div>
        </EditForm>
    </div>
</div>

@code {
    public const string PageUrl = "/pages/authentication/loginwithrecoverycode";
    private string? message;
    private ApplicationUser user = default!;

    [SupplyParameterFromForm] private InputModel Input { get; set; } = new();

    [SupplyParameterFromQuery] private string? ReturnUrl { get; set; }

    protected override async Task OnInitializedAsync()
    {
        // Ensure the user has gone through the username & password screen first
        user = await SignInManager.GetTwoFactorAuthenticationUserAsync() ??
               throw new InvalidOperationException(L["Unable to load two-factor authentication user."]);
    }

    private async Task OnValidSubmitAsync()
    {
        var recoveryCode = Input.RecoveryCode.Replace(" ", string.Empty);

        var result = await SignInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode);

        var userId = await UserManager.GetUserIdAsync(user);

        if (result.Succeeded)
        {
            Logger.LogInformation("User with ID '{UserId}' logged in with a recovery code.", userId);
            RedirectManager.RedirectTo(ReturnUrl);
        }
        else if (result.IsLockedOut)
        {
            Logger.LogWarning("User account locked out.");
            RedirectManager.RedirectTo(Lockout.PageUrl);
        }
        else
        {
            Logger.LogWarning("Invalid recovery code entered for user with ID '{UserId}' ", userId);
            message = L["Error: Invalid recovery code entered."];
        }
    }

    private sealed class InputModel
    {
        [Required]
        [DataType(DataType.Text)]
        [Display(Name = "Recovery Code")]
        public string RecoveryCode { get; set; } = "";
    }

}